﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

public class UIModelPanel : UIPanelEx
{
	HashSet<Renderer> psRenderMatMap = new HashSet<Renderer>();
	Dictionary<Renderer, List<Material>> renderMatMap = new Dictionary<Renderer, List<Material>>();
    Dictionary<Material, Material> matOldMatMap = new Dictionary<Material, Material>();
    public System.Func<UIModelPanel, string, int, List<Renderer>, int> setRenderersSortingOrderCallBack;


    #if UNITY_EDITOR
    static UIModelPanel()
    {
        EditorApplication.playmodeStateChanged += OnPlaymodeChanged;
    }

    static void OnPlaymodeChanged()
    {
        if (EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying)
        {
            UIModelPanel[] panels = GameObject.FindObjectsOfType<UIModelPanel>();
            for (int i = 0; i < panels.Length; i++)
            {
                panels[i].ResetRenderMaterials();
            }
            Selection.activeGameObject = null;
        }
    }
    #endif

    protected override void Awake ()
    {
        base.Awake();
        this.extraDrawcallCount = 0;
    }

    protected override void OnDisable()
    {
        ResetRenderMaterials();

        base.OnDisable();
    }

    protected override int UpdateDrawCalls(int sortOrder)
    {
        int sortingOrder = useSortingOrder ? ((this.sortingOrder == 0 && renderQueue == RenderQueue.Automatic) ? sortOrder : this.sortingOrder) : 0;
        string sortingLayerName = useSortingOrder ? this.sortingLayerName : null;

        // if(!useSortingOrder)
        // {
        //     if (!this.isActiveAndEnabled)
        //     {
        //         this.extraDrawcallCount = 0;
        //         return 0;
        //     }

        //     #if UNITY_EDITOR
        //     if (EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying)
        //     {
        //         ResetRenderMaterials();
        //         return 0;
        //     }

        //     if (!Application.isPlaying)
        //     {
        //         GameObject obj = Selection.activeObject as GameObject;
        //         if (obj == null || (obj != this.gameObject && !obj.transform.IsChildOf(this.gameObject.transform)))
        //         {
        //             ResetRenderMaterials();
        //             return 0;
        //         }
        //     }
        //     #endif


        //     int bgParticleRenderQueue = 0;
        //     int fgParticleRenderQueue = 0;
        //     List<UIParticleRenderQueue> uiBgEffects = this.gameObject.GetComponentsInChildrenEx<UIParticleRenderQueue>();
        //     for (int i = 0; i < uiBgEffects.Count; i++)
        //     {
        //         UIParticleRenderQueue uiBgEffect = uiBgEffects[i];
        //         ParticleSystemRenderer r = uiBgEffect.GetParticleSystemRenderer();
        //         if (r != null)
        //         {
        //             if (uiBgEffect.renderQueue < 0)
        //             {
        //                 bgParticleRenderQueue = Mathf.Max(bgParticleRenderQueue, -uiBgEffect.renderQueue);
        //             }
        //             else
        //             {
        //                 fgParticleRenderQueue = Mathf.Max(fgParticleRenderQueue, uiBgEffect.renderQueue);
        //             }
        //         }
        //     }



        //     for (int i = 0; i < uiBgEffects.Count; i++)
        //     {
        //         UIParticleRenderQueue uiBgEffect = uiBgEffects[i];
        //         ParticleSystemRenderer r = uiBgEffect.GetParticleSystemRenderer();
        //         if (r != null)
        //         {
        //             if (uiBgEffect.renderQueue < 0)
        //             {
        //                 FixRenderQueue(r, startingRenderQueue + bgParticleRenderQueue + uiBgEffect.renderQueue);
        //             }
        //         }
        //     }
        //     uiBgEffects.RecycleToListPool();

        //     int oldStartingRenderQueue = startingRenderQueue;
        //     startingRenderQueue += bgParticleRenderQueue;
        //     base.UpdateDrawCalls(sortOrder);
        
    	// 	int uiDrawCallNum = this.drawCalls.Count;

        //     List<Renderer> renderers = this.gameObject.GetComponentsInChildrenEx<Renderer>();
        //     for (int i = 0; i < renderers.Count; i++)
        //     {
    	// 		Renderer render = renderers[i];
    	// 		if (!(render is ParticleSystemRenderer))
    	// 		{
    	// 			FixRenderQueue(render, uiDrawCallNum + startingRenderQueue);
    	// 		}
        //     }

        //     for (int i = 0; i < renderers.Count; i++)
    	// 	{
    	// 		Renderer render = renderers[i];
    	// 		if (render is ParticleSystemRenderer)
    	// 		{
        //             UIParticleRenderQueue particleRenderQueue = null;
        //             for (int j = 0; j < uiBgEffects.Count; j++)
        //             {
        //                 if (uiBgEffects[j].GetParticleSystemRenderer() == render)
        //                 {
        //                     particleRenderQueue = uiBgEffects[j];
        //                     break;
        //                 }
        //             }

        //             int renderQueue = 0;
        //             if (particleRenderQueue != null)
        //             {
        //                 if (particleRenderQueue.renderQueue < 0)
        //                 {
        //                     continue;
        //                 }

        //                 renderQueue = particleRenderQueue.renderQueue;
        //             }

        //             FixRenderQueue(render, uiDrawCallNum + startingRenderQueue + 1 + renderQueue);
    	// 		}
    	// 	}
        //     renderers.RecycleToListPool();

        //     startingRenderQueue = oldStartingRenderQueue;
        //     extraDrawcallCount = bgParticleRenderQueue + fgParticleRenderQueue + 1 + 1;

        //     return 0;
        // }
        // else
        {
            base.UpdateDrawCalls(sortOrder);

            List<Renderer> renderers = this.gameObject.GetComponentsInChildrenEx<Renderer>();

            int ret = 0;
            if(setRenderersSortingOrderCallBack != null)
            {
                ret = setRenderersSortingOrderCallBack(this, sortingLayerName, sortingOrder, renderers);
            }
            else
            {
                for (int i = 0; i < renderers.Count; i++)
                {
                    Renderer render = renderers[i];
                    render.sortingOrder = sortingOrder;
                    render.sortingLayerName = sortingLayerName;
                }
            }
            renderers.RecycleToListPool();

            return ret;
        }
	}

    public int GetAssetMaterialCount()
    {
        return matOldMatMap.Count;
    }

    public void ResetRenderMaterials()
    {
        

//        Debug.LogError("ResetRenderMaterials");
		{
			Dictionary<Renderer, List<Material>>.Enumerator e = renderMatMap.GetEnumerator();
	        while (e.MoveNext())
	        {
				List<Material> mats = e.Current.Value;
	            for (int i = 0; i < mats.Count; i++)
	            {
	                Material m = mats[i];
	                if (m != null)
	                {
	                    Material oldMat = null;
	                    if (matOldMatMap.TryGetValue(m, out oldMat))
	                    {
	                        Material mat = mats[i];
	                        mats[i] = oldMat;

	//                        Debug.LogError("test ResetRenderMaterials: " + mat);

	                        if (Application.isPlaying)
	                        {
	                            GameObject.Destroy(mat);
	                        }
	                        else
	                        {
	                            GameObject.DestroyImmediate(mat, true);
	                        }
	                    }
	                }
	            }

	            if (e.Current.Key != null)
	            {
					e.Current.Key.SetSharedMaterialsEx(mats);
					UnityListPool<Material>.Recycle(mats);
	            }
	        }
		}
//		{
//			HashSet<Renderer>.Enumerator e = psRenderMatMap.GetEnumerator();
//			while (e.MoveNext())
//			{
//				Material m = e.Current.sharedMaterial;
//				if (m != null)
//				{
//					Material oldMat = null;
//					if (matOldMatMap.TryGetValue(m, out oldMat))
//					{
//						Material mat = m;
//						m = oldMat;
//
//						if (Application.isPlaying)
//						{
//							GameObject.Destroy(mat);
//						}
//						else
//						{
//							GameObject.DestroyImmediate(mat, true);
//						}
//					}
//				}
//
//				if (e.Current != null)
//				{
//					e.Current.sharedMaterial = m;
//				}
//			}
//		}
		psRenderMatMap.Clear();
        renderMatMap.Clear();
        matOldMatMap.Clear();
    }

	Material CreateMaterial(Material mat)
	{
//        if (Application.isPlaying)
		{
            if (!matOldMatMap.ContainsKey(mat))
            {
                Material newMat = GameObject.Instantiate (mat);
                matOldMatMap.Add(newMat, mat);
                mat = newMat;
            }

            return mat;
		}
//		else
//		{
//            return mat;
//		}
	}

	void FixRenderQueue(Renderer render, int renderQueue)
	{
		bool resetMat = false;

//		if(render is ParticleSystemRenderer)
//		{
//			psRenderMatMap.Add(render);
//
//			Material mat = render.sharedMaterial;
//			if (mat != null && mat.renderQueue != renderQueue)
//			{
//				mat = CreateMaterial(mat);
//				mat.renderQueue = renderQueue;
//				resetMat = true;
//			}
//			render.sharedMaterial = mat;
//		}
//		else
		{
	        List<Material> mats = null;
	        if (!renderMatMap.TryGetValue(render, out mats))
			{
				mats = render.GetSharedMaterialsEx();
				renderMatMap.Add(render, mats);
			}

			for (int i = 0; i < mats.Count; i++)
			{
				Material mat = mats[i];
				if (mat != null && mat.renderQueue != renderQueue)
				{
					mats[i] = CreateMaterial(mat);

					mats[i].renderQueue = renderQueue;
					resetMat = true;
				}
			}

	//		if (resetMat)
			{
				render.SetSharedMaterialsEx(mats);
			}
		}
	}

//	void Reset()
//	{
//		Dictionary<Renderer, Material[]>.Enumerator e = oldMaterials.GetEnumerator();
//		while (e.MoveNext())
//		{
//			Material[] mats = e.Current.Key.sharedMaterials;
//			for (int i = 0; i < mats.Length; i++)
//			{
//				ObjectPool.Recycle(mats[i]);
//			}
//
//			mats = e.Current.Value;
//			e.Current.Key.sharedMaterials = mats;
//		}
//
//		oldMaterials.Clear();
//	}
//
	protected virtual void OnDestroy()
	{
        ResetRenderMaterials();
	}

    void OnTransformChildrenChanged()
    {
        ResetRenderMaterials();
    }

//    void OnApplicationQuit()
//    {
//        Transform t = this.transform;
//        while(t.parent != null)
//        {
//            PrefabType pt = PrefabUtility.GetPrefabType(t.parent.gameObject);
//            if (pt != PrefabType.PrefabInstance)
//            {
//                break;
//            }
//
//            t = t.parent;
//        }
//
//        PrefabType pt2 = PrefabUtility.GetPrefabType(t.gameObject);
//        if (pt2 == PrefabType.PrefabInstance)
//        {
//            Debug.LogError("revert");
//            PrefabUtility.RevertPrefabInstance(t.gameObject);
//        }
//    }

//    void Reset()
//    {
//        EditorApplication.playmodeStateChanged
//        PrefabUtility.RevertPrefabInstance(this.gameObject);
//    }
}
